package com.king.armips.android.utils;

import android.os.Handler;
import android.os.HandlerThread;

import androidx.annotation.Nullable;

import java.util.HashMap;
import java.util.UUID;
import java.util.concurrent.atomic.AtomicInteger;

public class IoHandler {

    private HandlerThread mThread = null;
    private Handler mHandler = null;
    private final AtomicInteger mTaskCount = new AtomicInteger(0);

    private HashMap<Runnable,InnerRunnable> mActionMapping = new HashMap<>();

    public IoHandler(){
        super();
    }

    public void post(@Nullable Runnable r) {
        if (r == null)
            return;
        getHandler().post(new InnerRunnable(this,r));
    }

    public void postDelayed(@Nullable Runnable runnable, long delayMillis){
        if (runnable == null)
            return;
        getHandler().postDelayed(new InnerRunnable(this,runnable), delayMillis);
    }

    public void removeCallbacks(@Nullable Runnable r){
        if (r == null)
            return;
        InnerRunnable innerRunnable = mActionMapping.get(r);
        if (innerRunnable != null){
            getHandler().removeCallbacks(innerRunnable);
            mActionMapping.remove(r);
        }
    }

    private synchronized Handler getHandler(){
        if (mHandler == null){
            mThread = new HandlerThread("io-thread-"+ UUID.randomUUID().toString());
            mThread.start();
            mHandler = new Handler(mThread.getLooper());
        }
        return mHandler;
    }

    public void release(){
        if (mHandler != null){
            mHandler.removeCallbacksAndMessages(null);
            mHandler = null;
        }
        if (mThread != null) {
            mThread.quit();
            mThread = null;
        }
        mActionMapping.clear();
    }

    private static class InnerRunnable implements Runnable {
        private final IoHandler ioHandler;
        private final Runnable action;

        InnerRunnable(IoHandler ioHandler,Runnable action){
            this.ioHandler = ioHandler;
            this.action = action;
            ioHandler.mActionMapping.put(action,this);
        }

        @Override
        public void run() {
            ioHandler.mTaskCount.addAndGet(1);

            try {
                action.run();
            }catch (Exception e){
                e.printStackTrace();
            }

            if (ioHandler.mTaskCount.addAndGet(-1) == 0){
                ioHandler.release();
            }
        }
    }

}